package tianrun.ziguan.api.forecast.util;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.format.datetime.DateFormatterRegistrar;
import org.springframework.objenesis.instantiator.sun.MagicInstantiator;
import tianrun.ziguan.api.forecast.handler.GlobalExceptionHandler;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

public class DateUtils {

	private final static Logger log = LoggerFactory.getLogger(DateUtils.class);

    public final static String FORMATTER1 = "yyyy-MM-dd";

    private final static String FORMATTER2 = "yyyy-MM-dd HH:mm:ss";

    private final static String FORMATTER3 = "yyyy-MM-dd HH:mm";

    private final static String FORMATTER4 = "yyyy-MM";

    private final static ZoneId ZONE_ID = ZoneId.of("Asia/Shanghai");

    private final static String CRON = "ss mm HH dd MM ? yyyy";

    /**
     * 获取当前日期
     *
     * @return
     */
    public static String nowDate() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(FORMATTER1);
        LocalDateTime now = nowLocalDateTime();
        return now.format(formatter);
    }

    /**
     * 获取当前时间
     */
    public static String nowFullTime() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(FORMATTER2);
        LocalDateTime now = LocalDateTime.now();
        return now.format(formatter);
    }

    /**
     * 获取当前时间
     */
    public static LocalDateTime nowLocalDateTime() {
        ZoneId zoneId = ZoneId.of("UTC+8");
        return LocalDateTime.now(zoneId);
    }

    public static LocalDateTime nowLocalDateTimeShangHai() {
        return LocalDateTime.now(ZONE_ID);
    }

    /**
     * 格式化时间  yyyy-MM-dd HH:mm:ss
     *
     * @param dateTime
     * @return
     */
    public static String formatFullTime(LocalDateTime dateTime) {
        if (dateTime == null) {
            return "";
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(FORMATTER2);
        return dateTime.format(formatter);
    }


	public static String formatFullTime(Date dateTime) {
		if (dateTime == null) {
			return "";
		}
		SimpleDateFormat dateFormat = new SimpleDateFormat(FORMATTER2);
		return dateFormat.format(dateTime);
	}


	public static String formatDate(Date dateTime) {
		if (dateTime == null) {
			return "";
		}
		SimpleDateFormat dateFormat = new SimpleDateFormat(FORMATTER1);
		return dateFormat.format(dateTime);
	}


    public static String formatYearAndMonth(Date dateTime) {
        if (dateTime == null) {
            return "";
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat(FORMATTER4);
        return dateFormat.format(dateTime);
    }

    /**
     * 当前日期前n天
     *
     * @param n
     * @return
     */
    public static String afterFromNow(int n) {
        SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
        Calendar c = Calendar.getInstance();
        c.add(Calendar.DATE, n);
        return s.format(c.getTime());
    }


    /**
     * 格式化时间  yyyy-MM-dd HH:mm:ss
     *
     * @param dateTime
     * @return
     */
    public static String longToString(Long dateTime) {
        return formatFullTime(parseLocalDateTime(dateTime));
    }

    public static LocalDateTime formatDate(String time) {
        if (StringUtils.isEmpty(time)) {
            return null;
        }
        DateTimeFormatter df = DateTimeFormatter.ofPattern(FORMATTER1);
        LocalDateTime ldt;
        try {
            LocalDate localDate = LocalDate.parse(time, df);
            ldt = localDate.atStartOfDay();
        } catch (Exception e) {
            return null;
        }
        return ldt;
    }


    public static LocalDateTime formatFullTime(String time) {
        if (StringUtils.isEmpty(time)) {
            return null;
        }
        DateTimeFormatter df = DateTimeFormatter.ofPattern(FORMATTER2);
        LocalDateTime ldt;
        try {
            ldt = LocalDateTime.parse(time, df);
        } catch (Exception e) {
            return null;
        }
        return ldt;
    }

    public static LocalDateTime formatToMinute(String time) {
        if (StringUtils.isEmpty(time)) {
            return null;
        }
        DateTimeFormatter df = DateTimeFormatter.ofPattern(FORMATTER3);
        LocalDateTime ldt;
        try {
            ldt = LocalDateTime.parse(time, df);
        } catch (Exception e) {
            return null;
        }
        return ldt;
    }


    /**
     * 将LocalDateTime转为long
     */
    public static Long parseLong(LocalDateTime time) {
        if (time == null) {
            return null;
        }
        return time.atZone(ZONE_ID).toInstant().toEpochMilli();
    }

    /**
     * 将long转为LocalDateTime
     */
    public static LocalDateTime parseLocalDateTime(Long time) {
        if (time == null) {
            return null;
        }
        return Instant.ofEpochMilli(time).atZone(ZONE_ID).toLocalDateTime();
    }

    public static String getCronStr(LocalDateTime time) {
        return time.format(DateTimeFormatter.ofPattern(CRON));
    }

    public static Long nowTimeLong() {
        return LocalDateTime.now().atZone(ZONE_ID).toInstant().toEpochMilli();
    }

    /**
     * 与当前系统时间计算时间差 分钟数
     */
    public static Long minutesBetween(LocalDateTime begin) {
        return minutesBetween(begin, nowLocalDateTimeShangHai());
    }

    /**
     * 计算时间差 分钟数
     */
    public static Long minutesBetween(LocalDateTime begin, LocalDateTime finish) {
        long ret = begin.until(finish, ChronoUnit.MINUTES);
        return ret < 0 ? -ret : ret;
    }

    /**
     * 某年月日:00:00:00,23:59:59
     *
     * @param time
     * @return
     */
    public static Date[] getStartEndDay(String time) {
        String[] split = time.split("-");
        GregorianCalendar gregorianCalendar = new GregorianCalendar(Integer.valueOf(split[0]), Integer.valueOf(split[1]) - 1, Integer.valueOf(split[2]));

        //一天的开始时间 yyyy:MM:dd 00:00:00
        gregorianCalendar.set(Calendar.HOUR_OF_DAY, 0);
        gregorianCalendar.set(Calendar.MINUTE, 0);
        gregorianCalendar.set(Calendar.SECOND, 0);
        gregorianCalendar.set(Calendar.MILLISECOND, 0);
        Date dayStart = gregorianCalendar.getTime();


        //一天的结束时间 yyyy:MM:dd 23:59:59
        gregorianCalendar.set(Calendar.HOUR_OF_DAY, 23);
        gregorianCalendar.set(Calendar.MINUTE, 59);
        gregorianCalendar.set(Calendar.SECOND, 59);
        gregorianCalendar.set(Calendar.MILLISECOND, 999);
        Date dayEnd = gregorianCalendar.getTime();

        return new Date[]{dayStart, dayEnd};
    }

	/**
	 * 某年月日:00:00:00,23:59:59
	 *
	 * @param time
	 * @return
	 */
	public static Date getStartDay(String time) {
		String[] split = time.split("-");
		GregorianCalendar gregorianCalendar = new GregorianCalendar(Integer.valueOf(split[0]), Integer.valueOf(split[1]) - 1, Integer.valueOf(split[2]));

		//一天的结束时间 yyyy:MM:dd 23:59:59
		gregorianCalendar.set(Calendar.HOUR_OF_DAY, 23);
		gregorianCalendar.set(Calendar.MINUTE, 59);
		gregorianCalendar.set(Calendar.SECOND, 59);
		gregorianCalendar.set(Calendar.MILLISECOND, 999);
		return gregorianCalendar.getTime();
	}

	/**
	 * 某年月日:00:00:00,23:59:59
	 *
	 * @param time
	 * @return
	 */
	public static Date getEndDay(String time) {
		String[] split = time.split("-");
		GregorianCalendar gregorianCalendar = new GregorianCalendar(Integer.valueOf(split[0]), Integer.valueOf(split[1]) - 1, Integer.valueOf(split[2]));

		//一天的开始时间 yyyy:MM:dd 00:00:00
		gregorianCalendar.set(Calendar.HOUR_OF_DAY, 0);
		gregorianCalendar.set(Calendar.MINUTE, 0);
		gregorianCalendar.set(Calendar.SECOND, 0);
		gregorianCalendar.set(Calendar.MILLISECOND, 0);
		return gregorianCalendar.getTime();
	}


    /**
     * 转换前:某年月日:2019-01-15
     * 转换后:2019-01-01
     * @param time
     * @return
     */
    public static String getStartDate(String time) {
        String[] split = time.split("-");
        GregorianCalendar gregorianCalendar = new GregorianCalendar(Integer.valueOf(split[0]), Integer.valueOf(split[1]) - 1, 1);


        return formatDate(gregorianCalendar.getTime());
    }

    /**
     * 转换前:某年月日:2019-01-15
     * 转换后:2019-01-31
     * @param time
     * @return
     */
    public static String getEndDate(String time) {
        String[] split = time.split("-");
        GregorianCalendar gregorianCalendar = new GregorianCalendar(Integer.valueOf(split[0]), Integer.valueOf(split[1]) , 0);
        return formatDate(gregorianCalendar.getTime());
    }

    /**
     * 转换前:某年月日:2019-01-15
     * 转换后:2019-01-01
     * @param time
     * @return
     */
    public static String getStartDateWithYear(String time) {
        String[] split = time.split("-");
        GregorianCalendar gregorianCalendar = new GregorianCalendar(Integer.valueOf(split[0]), 0, 1);


        return formatDate(gregorianCalendar.getTime());
    }

    /**
     * 转换前:某年月日:2019-01-15
     * 转换后:2019-12-31
     * @param time
     * @return
     */
    public static String getEndDateWithYear(String time) {
        String[] split = time.split("-");
        GregorianCalendar gregorianCalendar = new GregorianCalendar(Integer.valueOf(split[0])+1, 0 , 0);
        return formatDate(gregorianCalendar.getTime());
    }


    private static ThreadLocal<Date> dateLocal = new ThreadLocal<Date>() {

        @Override
        protected Date initialValue() {
            return new Date();
        }
    };

    private static ThreadLocal<Calendar> calendarLocal = new ThreadLocal<Calendar>() {

        @Override
        protected Calendar initialValue() {
            return Calendar.getInstance(TimeZone.getTimeZone("GMT+8:00"));
        }
    };

    /**
     * 获取时间date 如果str为null或者"" 则返回当前时间date
     *
     * @param str    时间字符串
     * @param format 时间字符串格式（如str为：2018_05_29 12:12:00; 则format即为：yyyy_MM_dd
     *               HH:mm:ss）
     * @return date
     */
    public static Date getDateByString(String str, String format) {
        Date date = null;
        if (str == null || "".equals(str)) {
            return dateLocal.get();
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
			try {
				date = sdf.parse(str);
			} catch (ParseException e) {
				log.error("时间转换异常",e);
			}
		}
        return date;
    }

    public static Date dateFormatEtc(String dateString, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        Date date = null;
        try {
            sdf.setTimeZone(TimeZone.getTimeZone("Etc/GMT-8"));
            date = sdf.parse(dateString);
        } catch (ParseException e) {
            log.error("时间转换异常", e);
        }
        return date;
    }


    /**
     * 通过时间date 获取此时间的前几天或者后几天的时间date 如果date为null 则返回当前时间的前几天或者后几天date
     *
     * @param date  指定时间date
     * @param count 过去退几天（负数）， 未来前进几天（正数）
     * @return date
     */
    public static Date getDateByDate(Date date, int count) throws Exception {
        Calendar ca = calendarLocal.get();
        if (date == null) {
            date = dateLocal.get();
        }
        ca.setTime(date);
        ca.add(Calendar.DAY_OF_MONTH, count);
        return ca.getTime();
    }

	/**
	 * 获取某年月日的t+3日
	 * @param dateStr
	 * @return
	 */
	public static String getPlusThreeDate(String dateStr){
		Date dateByString = getDateByString(dateStr, FORMATTER1);
		Date dateByDate = null;
		try {
			dateByDate = getDateByDate(dateByString, 3);
		} catch (Exception e) {
			log.error("时间转换异常",e);
		}
		return formatDate(dateByDate);
	}

    /**
     * 获取某年月日的t-3日
     * @param dateStr
     * @return
     */
    public static String getMinusThreeDate(String dateStr){
        Date dateByString = getDateByString(dateStr, FORMATTER1);
        Date dateByDate = null;
        try {
            dateByDate = getDateByDate(dateByString, -3);
            log.info("dateByDate======{}dateByString======{},",dateByDate,dateByString);
        } catch (Exception e) {
            log.error("时间转换异常",e);
        }
        return formatDate(dateByDate);
    }


    public static Map<String,String> getDataRange(String minDate, String maxDate){
        log.info("mindate=============={},maxDate=========={}",minDate,maxDate);
        Map<String,String>map = new HashMap<>();
        LocalDate min = LocalDate.parse(minDate);
        min = min.with(TemporalAdjusters.firstDayOfMonth());
        log.info("开始==={}",min.format(DateTimeFormatter.ofPattern("yyyy-MM")));
        LocalDate max = LocalDate.parse(maxDate);
        max = max.with(TemporalAdjusters.firstDayOfMonth());
        log.info("结束==={}",max.format(DateTimeFormatter.ofPattern("yyyy-MM")));


        long i = 0L;
        while (min.isBefore(max)||min.isEqual(max)){
            map.put(String.valueOf(i),min.format(DateTimeFormatter.ofPattern("yyyy-MM")));
            min = min.plusMonths(1);
            i++;
        }

        if (map.isEmpty()){
            map.put(String.valueOf(0),min.format(DateTimeFormatter.ofPattern("yyyy-MM")));
        }
        return map;
    }


    public static Map<String,String>getDayRange(String startDate,String endDate){
        Map<String,String>map = new HashMap<>();
        Date d1 = null;//定义起始日期
        try {
            d1 = new SimpleDateFormat("yyyy-MM-dd").parse(startDate);
        } catch (ParseException e) {
            log.error("日期范围转换失败"+e);
        }

        Date d2 = null;//定义结束日期
        try {
            d2 = new SimpleDateFormat("yyyy-MM-dd").parse(endDate);
        } catch (ParseException e) {
            log.error("日期范围转换失败"+e);
        }

        Calendar dd = Calendar.getInstance();//定义日期实例

        dd.setTime(d1);//设置日期起始时间
        int i = 0;
        while(dd.getTime().before(d2)){//判断是否到结束日期

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

            String str = sdf.format(dd.getTime());
            map.put(String.valueOf(i),str);

            dd.add(Calendar.DAY_OF_MONTH, 1);//进行当前日期月份加1
            i++;
        }
        if (map.isEmpty()){
            map.put(String.valueOf(0),startDate);
        }else {
            map.put(String.valueOf(i),endDate);
        }

        return map;
    }

    public static String parseDateLocalDateTime(LocalDateTime time){
        return time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }



	public static void main(String[] args) throws Exception {


        String s = "2019-01-31";
        String d = "2019-02-01";
        ///Map<String, String> dayRange = getDayRange(s, d);
        Map<String, String> dataRange = DateUtils.getDataRange(s.substring(0, s.lastIndexOf("-")), d.substring(0, d.lastIndexOf("-")));
        System.out.println(dataRange);
        System.out.println(s.substring(0,s.lastIndexOf("-")));

    }
}